// <copyright file="Button.cs" company="YUIAsp.Net">
// Copyright (c) 2009 All Right Reserved
// </copyright>
// <author>raul popescu</author>
// <email>dev@yuiasp.net</email>
// <date>2009-01-30</date>
// <summary>YUIAsp.Net File</summary>

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Design;
using System.Globalization;
using System.Web;
using System.Web.UI;
using YUIAspNet.Common;

#region Button assets registration
[assembly: WebResource("YUIAspNet.Button.Button.js", "text/javascript")]

[assembly: WebResource("YUIAspNet.EmbeddedSkins.DefaultSkin.Button.button-core.css", "text/css", PerformSubstitution = true)]
[assembly: WebResource("YUIAspNet.EmbeddedSkins.DefaultSkin.Button.button.css", "text/css", PerformSubstitution = true)]
[assembly: WebResource("YUIAspNet.EmbeddedSkins.DefaultSkin.Button.button-skin.css", "text/css", PerformSubstitution = true)]
[assembly: WebResource("YUIAspNet.EmbeddedSkins.DefaultSkin.sprite.png", "image/png")]
[assembly: WebResource("YUIAspNet.EmbeddedSkins.DefaultSkin.Button.split-button-arrow.png", "image/png")]
[assembly: WebResource("YUIAspNet.EmbeddedSkins.DefaultSkin.Button.split-button-arrow-active.png", "image/png")]
[assembly: WebResource("YUIAspNet.EmbeddedSkins.DefaultSkin.Button.split-button-arrow-disabled.png", "image/png")]
[assembly: WebResource("YUIAspNet.EmbeddedSkins.DefaultSkin.Button.split-button-arrow-focus.png", "image/png")]
[assembly: WebResource("YUIAspNet.EmbeddedSkins.DefaultSkin.Button.split-button-arrow-hover.png", "image/png")]
[assembly: WebResource("YUIAspNet.EmbeddedSkins.DefaultSkin.Button.menu-button-arrow.png", "image/png")]
[assembly: WebResource("YUIAspNet.EmbeddedSkins.DefaultSkin.Button.menu-button-arrow-disabled.png", "image/png")]
#endregion

namespace YUIAspNet
{
    /// <summary>
    /// Event args super-class, used on a Button click.
    /// </summary>
    [ToolboxItem(false)]
    [ParseChildren(true)]
    public class ButtonEventArgs : EventArgs 
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ButtonEventArgs"/> class.
        /// </summary>
        /// <param name="item">The item.</param>
        public ButtonEventArgs(MenuItem item)
        {
            this.Item =item;
        }

        /// <summary>
        /// Gets or sets the item.
        /// </summary>
        /// <value>The item.</value>
        public MenuItem Item { get; set; }
    }

    /// <summary>
    /// Button control
    /// </summary>
    [ToolboxItem(true)]
    //[Designer(typeof(ButtonDesigner))]
    [DefaultProperty("Text")]
    public class Button : YUIScriptBaseControl, INamingContainer, IPostBackDataHandler
    {
        private const string BUTTONID = "btn";

        /// <summary>
        /// Occurs when the button is clicked.
        /// </summary>
        public event EventHandler<ButtonEventArgs> Click;

        /// <summary>
        /// Initializes a new instance of the <see cref="Button"/> class.
        /// </summary>
        public Button()
        {
            this.ButtonType = ButtonType.Regular;

            ControlKey = "Button";

            this.Load += new EventHandler(Button_Load);
            this.PreRender += new EventHandler(Button_PreRender);
        }

        void Button_Load(object sender, EventArgs e)
        {
            RegisterMenuClick();
        }

        /// <summary>
        /// Registers the menu click.
        /// </summary>
        protected virtual void RegisterMenuClick()
        {
            //register menu click as default handler for button!
            if (this.ButtonMenu != null)
                this.ButtonMenu.Click += new EventHandler<MenuClickEventArgs>(ButtonMenu_Click);
        }

        void ButtonMenu_Click(object sender, MenuClickEventArgs e)
        {
            if (this.Click != null) Click(sender, new ButtonEventArgs(e.Item));
        }

        /// <summary>
        /// Called by the ASP.NET page framework to notify server controls that use composition-based implementation to create any child controls they contain in preparation for posting back or rendering.
        /// </summary>
        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            this.Checked = false;

            if (this is OverlayButton)
            { }
            else
            {
                if (this.ButtonMenu == null)
                    this.ButtonMenu = new Menu();

                this.ButtonMenu.ID = "buttonMenu";
                this.ButtonMenu.AutoInitialize = false;
                this.ButtonMenu.MenuType = MenuType.Dynamic;

                this.Controls.Add(ButtonMenu);
            }
        }

        void Button_PreRender(object sender, EventArgs e)
        {
            if ((this.Page != null))
                this.Page.RegisterRequiresPostBack(this);
        }

        /// <summary>
        /// Registers the style sheets for the current control.
        /// Must be overriden in the parent control to add any css file reference.
        /// </summary>
        protected override void RegisterStyleSheets()
        {
            RegisterEmbeddedStylesheet("Button", "button.css");
        }

        /// <summary>
        /// Register the values to send to the client control for initialization.
        /// </summary>
        protected override void RegisterClientInitialization()
        {
            AddProperty("ButtonID", string.Concat(this.ClientID, this.ClientIDSeparator, BUTTONID));
            AddProperty("ButtonName",  string.Concat(this.UniqueID, this.IdSeparator, BUTTONID));
            AddProperty("TabIndex", this.TabIndex);

            string buttonType = this.ButtonType == ButtonType.Regular ? "push" : this.ButtonType.ToString().ToLower(CultureInfo.InvariantCulture);

            AddProperty("ButtonType", buttonType);
            AddProperty("Text", this.Text);

            if (this.ButtonType == ButtonType.Link)
            {
                AddProperty("NavigateUrl", NavigateUrl.AbsolutePath);

                AddProperty("Target", this.Target);
            }

            if (this.ButtonType == ButtonType.Split
                    || this.ButtonType == ButtonType.Menu
                )
            {
                if (this is OverlayButton)
                { }
                else
                {
                    AddProperty("MenuContainer", this.ButtonMenu.ClientID);
                }
            }
            else ButtonMenu.Visible = false;

            if (this.ButtonType == ButtonType.Checkbox)
            {
                AddProperty("Checked", this.Checked);
                AddProperty("Value", this.Value);

                this.Page.ClientScript.RegisterHiddenField(this.ClientID + "_state", this.Checked ? "1" : "0");
            }

            if (!string.IsNullOrEmpty(this.OnClientClick))
                AddEvent("onClick", this.OnClientClick);
        }

        /// <summary>
        /// Registers any additional scripts to include for this control.
        /// </summary>
        protected override void RegisterScriptReferences()
        {
            if (this.ButtonType == ButtonType.Split
                            || this.ButtonType == ButtonType.Menu)
            {
                AddScriptReference(this.GetScriptRerefenceFromScriptType(YUIScriptName.Container));
                AddScriptReference(this.GetScriptRerefenceFromScriptType(YUIScriptName.Menu));
            }

            AddScriptReference(new ScriptReference("YUIAspNet.Button.Button.js", typeof(Button).Assembly.FullName));
        }

        #region IPostBackDataHandler Members

        /// <summary>
        /// When implemented by a class, processes postback data for an ASP.NET server control.
        /// </summary>
        /// <param name="postDataKey">The key identifier for the control.</param>
        /// <param name="postCollection">The collection of all incoming name values.</param>
        /// <returns>
        /// true if the server control's state changes as a result of the postback; otherwise, false.
        /// </returns>
        public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
        {
            if (this.ButtonType == ButtonType.Checkbox)
                this.Checked = postCollection[this.ClientID + "_state"] == "1";

            //post from button
            if (postCollection[this.ClientID] != null
                || postCollection["__EVENTTARGET"] == this.ClientID)
                return true;

            return false;
        }

        /// <summary>
        /// When implemented by a class, signals the server control to notify the ASP.NET application that the state of the control has changed.
        /// </summary>
        public void RaisePostDataChangedEvent()
        {
            if (this.Click != null)
            {
                ButtonEventArgs args = new ButtonEventArgs(null);
                if (this.ButtonType == ButtonType.Split || this.ButtonType == ButtonType.Menu)
                {
                    foreach (MenuItem item in this.ButtonMenu.Items)
                    {
                        if (HttpContext.Current.Request.Form["__EVENTARGUMENT"] == item.Value)
                            args.Item = item;
                    }
                }
                this.Click(this, args);
            }
        }
        #endregion

        #region Public properties
        /// <summary>
        /// Get / set the client side click handler.
        /// Handler gets 2 parameters: the sender(instance of the Button client side class) and arguments.
        /// </summary>
        public string OnClientClick
        {
            get { return ViewState["OnClientClick"] as string; }
            set { ViewState["OnClientClick"] = value; }
        }

        /// <summary>
        /// Get / set the button type
        /// </summary>
        public ButtonType ButtonType
        {
            get { return (ButtonType)ViewState["ButtonType"]; }
            set { ViewState["ButtonType"] = value; }
        }

        /// <summary>
        /// Get / set the text
        /// </summary>
        public string Text
        {
            get { return ViewState["Text"] as string; }
            set { ViewState["Text"] = value; }
        }

        /// <summary>
        /// Get / set the target of the button acting as a anchor.
        /// This property is considered when button's type is Link
        /// </summary>
        [DefaultValue(""), TypeConverter(typeof(System.Web.UI.WebControls.TargetConverter))]
        public string Target
        {
            get { return ViewState["Target"] as string; }
            set { ViewState["Target"] = value; }
        }

        /// <summary>
        /// Get / set the URL to redirect when clicked.
        /// This property is considered when button's type is Link
        /// </summary>
        [Bindable(true), DefaultValue(""), UrlProperty, Editor("System.Web.UI.Design.UrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        public Uri NavigateUrl
        {
            get { return ViewState["NavigateUrl"] as Uri; }
            set { ViewState["NavigateUrl"] = value; }
        }

        /// <summary>
        /// Gets or sets the button menu.
        /// </summary>
        /// <value>The button menu.</value>
        [Category("Data"), Description("Button options.")]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public virtual Menu ButtonMenu { get; set; }

        /// <summary>
        /// Get / set the check state of the control.
        /// This property is considered when button's type is Checkbox
        /// </summary>
        public bool Checked
        {
            get { return (bool)ViewState["Checked"]; }
            set { ViewState["Checked"] = value; }
        }

        /// <summary>
        /// Get / set the string value of the control.
        /// </summary>
        public string Value
        {
            get { return ViewState["Value"] as string; }
            set { ViewState["Value"] = value; }
        }

        /// <summary>
        /// Gets or sets the selected item.
        /// </summary>
        /// <value>The selected item.</value>
        public RadioButtonItem SelectedItem { get; set; } 
        #endregion
    }
}
